package cn.tang.tframe.sdm.aop.wrapper;

import cn.tang.tframe.common.utils.lang.CollectionUtils;
import cn.tang.tframe.sdm.aop.handler.AopHandler;
import cn.tang.tframe.sdm.aop.handler.ExceptionHandler;
import cn.tang.tframe.sdm.aop.handler.PreHandler;
import cn.tang.tframe.sdm.aop.handler.FinalHandler;
import org.aspectj.lang.ProceedingJoinPoint;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by tanghc on 17/1/18.
 */
public class CommonAopServiceWrapper implements AopWrapper {
	protected List<PreHandler> preHandlers = new ArrayList<>();
	protected List<ExceptionHandler> exceptionHandlers = new ArrayList<>();
	protected List<FinalHandler> finalHandlers = new ArrayList<>();

	@Override
	public void addHandlers(AopHandler handler){
		if(null != handler){
			if(handler instanceof PreHandler){
				preHandlers.add((PreHandler)handler);
			}else if(handler instanceof ExceptionHandler){
				exceptionHandlers.add((ExceptionHandler)handler);
			}else if(handler instanceof FinalHandler){
				finalHandlers.add((FinalHandler)handler);
			}
		}
	}

	@Override
	public Object wrap(ProceedingJoinPoint pjp) throws Exception {
		Object[] args = null;
		Object result = null;
		long starttime = System.currentTimeMillis();
		try {

			if(CollectionUtils.isNotEmpty(preHandlers)){
				for(PreHandler handler: preHandlers){
					handler.setStartTime(starttime);
					if(!handler.handler(pjp)){
						break;
					}
				}
			}
			args = pjp.getArgs();
			result = pjp.proceed(args);
			return result;
		} catch (Throwable throwable) {
			Exception e = null;
			if(throwable instanceof Exception){
				e = (Exception)throwable;
			}else{
				e = new Exception(throwable);
			}
			if(CollectionUtils.isNotEmpty(exceptionHandlers)){
				for(ExceptionHandler handler: exceptionHandlers){
					handler.setTargetException(e);
					if(!handler.handler(pjp)){
						break;
					}
				}
			}
			return returnWhenException(pjp,e);
		} finally {
			long endtime = System.currentTimeMillis();
			if(CollectionUtils.isNotEmpty(finalHandlers)){
				for(FinalHandler handler: finalHandlers){
					handler.setEndTime(endtime);
					handler.setEndTime(endtime - starttime);
					handler.setResult(result);
					if(!handler.handler(pjp)){
						break;
					}
				}
			}
		}
	}
	protected Object returnWhenException(ProceedingJoinPoint pjp,Exception e) throws Exception {
		throw e;
	}
}
